Lets us read the file.
library(readr)
lyrics <- read_csv("songdata.csv")
Parsed with column specification:
cols(
artist = col_character(),
song = col_character(),
link = col_character(),
text = col_character()
)
head(lyrics)
Lets us examine the dimension of the lyrics dataframe.
dim(lyrics)
[1] 57650 4
library(dplyr)
glimpse(lyrics)
Observations: 57,650
Variables: 4
$ artist <chr> "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "A...
$ song <chr> "Ahe's My Kind Of Girl", "Andante, Andante", "As Good As New", "Bang", "Bang-A-Boomerang", "Burnin...
$ link <chr> "/a/abba/ahes+my+kind+of+girl_20598417.html", "/a/abba/andante+andante_20002708.html", "/a/abba/as...
$ text <chr> "Look at her face, it's a wonderful face \nAnd it means something special to me \nLook at the wa...
Analysis of 55000+ lyrics data - Number of artists - Which artist has highest and lowest number of songs - Distribution of songs of all artists in the dataset - Distribution of lyrics length - Which song lyrics has maximum number of words - Which song lyrics has minimum number of words - Distribution of words count in title - Which songs title has maximum number of words - Which songs title has minimum number of words - WordClouds of titles with minimum and maximum lengths - Is there a relation between title length and song length?
- Sentiments of the songs (NRC, Bing)
- Which words are most occuring in the lyrics of the songs
- Is there a correlation between the words in the songs of same artists?
- Wordcloud of most popular words in the songs
- Top words used by an artist in his/her songs
- Are there some common Rythmic words that repeats again and again?
Let’s start with finding out how many artists are listed in the data. Also, how many songs each artist has.
artist<- as.data.frame(table(as.data.frame(lyrics$artist)))
colnames(artist) <- c("artist", "Num_of_songs")
head(artist)
Let’s see the which artist has most and least number of songs in the dataset.
most_songs <- arrange(artist, desc(Num_of_songs))
most_songs

least_songs <- tail(most_songs, 15)
p2 <- ggplot(data = least_songs, aes(artist, Num_of_songs, fill = Num_of_songs)) +
geom_bar(stat = "identity") +
geom_text(aes(label=Num_of_songs), vjust=1.6, color="white", size=3) +
ggtitle("Artists with least number of songs") +
tilt_theme
p2

Let’s check the distribution of songs for all artists.
p3 <- ggplot(artist, aes(x=Num_of_songs)) +
geom_histogram(aes(y=..density..), colour="black", fill="white")+
geom_density(alpha=.2, fill="red")
p3

Let’s analyze the number of words in each song and its distribution.
library(stringr)
count_words <- function(vec){
return (length(unlist((str_extract_all(tolower(vec), '\\w+')))))
}
lyrics$word_count <- sapply(lyrics$text, count_words)
head(lyrics$word_count)
[1] 161 272 322 257 255 115
p4 <- ggplot(lyrics, aes(x=word_count)) +
geom_histogram(aes(y=..density..), colour="black", fill="white")+
geom_density(alpha=.2, fill="red")
p4

Let’s analyze the title of the songs, their wordcount and their distribution
lyrics$title_word_count <- sapply(lyrics$song, count_words)
head(lyrics$title_word_count)
[1] 6 2 4 1 3 3
Let’s check out the songs that are longest and shortest.
longest_song <- arrange(lyrics, desc(word_count))
longest_song <- head(longest_song, 10)
shortest_song <- arrange(lyrics, word_count)
shortest_song <- head(shortest_song, 10)
longest_song
shortest_song
p5 <- ggplot(data = longest_song, aes(song, word_count, fill = title_word_count)) +
geom_bar(stat = "identity") +
geom_text(aes(label=title_word_count), vjust=1.6, color="white", size=3) +
ggtitle("Longest Songs") +
tilt_theme
p6 <- ggplot(data = shortest_song, aes(song, word_count, fill = title_word_count)) +
geom_bar(position = "dodge", stat = "identity") +
geom_text(aes(label = title_word_count), vjust = 1.6, color = "white", size = 3) +
ggtitle("Shortest Songs") +
tilt_theme
multiplot(p5, p6, cols=2)

p7 <- ggplot(lyrics, aes(x=title_word_count)) +
geom_histogram(aes(y=..density..), colour="black", fill="white", binwidth = 1, bins = 1)+
geom_density(alpha=.2, fill="red")
p7

WordCloud of popular words from song titles
library(wordcloud)
library(SnowballC)
library(RColorBrewer)
library(tm)
texts <- lyrics$song
#texts <- iconv(texts, to = "utf-8")
corpus <- Corpus(VectorSource(texts))
corpus <- tm_map(corpus, PlainTextDocument)
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeWords, stopwords('english'))
corpus <- tm_map(corpus, stemDocument)
corpus <- tm_map(corpus, removeWords, c("and", "this", "there"))
corpus <- Corpus(VectorSource(corpus))
dtm <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
head(d, 10)
d <- d[-which(d$word %in% c("and","this","that")),]
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1,
max.words=200, random.order=FALSE, rot.per=0.35,
colors=brewer.pal(8, "Dark2"))

There are many song titles that are of length 1, 2 and 3. But surprisingly, there are titles of length more than 13 too. Let’s check them out.
longest_title <- subset(lyrics, lyrics$title_word_count > 13)
longest_title
shortest_title <- subset(lyrics, lyrics$title_word_count == 1)
shortest_title
There are 8 songs with title length more than 13 and 8342 songs with single word title. Let’s see word cloud of single word titles and longest titles
texts <- longest_title$song
corpus <- Corpus(VectorSource(texts))
corpus <- tm_map(corpus, PlainTextDocument)
corpus <- Corpus(VectorSource(corpus))
dtm <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
head(d, 10)
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1,scale=c(2,0.5),
max.words=100, random.order=FALSE, rot.per=0.35,
colors=brewer.pal(8, "Dark2"))

texts <- shortest_title$song
corpus <- Corpus(VectorSource(texts))
corpus <- tm_map(corpus, PlainTextDocument)
corpus <- Corpus(VectorSource(corpus))
dtm <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
head(d, 10)
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1,scale=c(2,0.5),
max.words=100, random.order=FALSE, rot.per=0.35,
colors=brewer.pal(8, "Dark2"))

An interesting questin would be is there relation between length of title and songs? Most probably now, but let’s check out.
p8 <- ggplot(lyrics, aes(x=factor(title_word_count), y=word_count, fill = factor(title_word_count))) +
geom_boxplot()
p8

cor(lyrics$title_word_count, lyrics$word_count)
[1] -0.02509779
As expected, there is no correlation between these two quantitites.
Let us fix the contracted words to their full forms first.
# function to expand contractions in an English-language source
fix.contractions <- function(doc) {
# "won't" is a special case as it does not expand to "wo not"
doc <- gsub("won't", "will not", doc)
doc <- gsub("can't", "can not", doc)
doc <- gsub("n't", " not", doc)
doc <- gsub("'ll", " will", doc)
doc <- gsub("'re", " are", doc)
doc <- gsub("'ve", " have", doc)
doc <- gsub("'m", " am", doc)
doc <- gsub("'d", " would", doc)
# 's could be 'is' or could be possessive: it has no expansion
doc <- gsub("'s", "", doc)
return(doc)
}
# fix (expand) contractions
lyrics$text <- sapply(lyrics$text, fix.contractions)
Remove special characters from lyrics
# function to remove special characters
removeSpecialChars <- function(x) gsub("[^a-zA-Z0-9 ]", " ", x)
# remove special characters
lyrics$text <- sapply(lyrics$text, removeSpecialChars)
Convert all lyrics text to lower case
# convert everything to lower case
lyrics$text <- sapply(lyrics$text, tolower)
Let’s check the structure of one lyrics to see the changes.
str(lyrics[13, ]$text, nchar.max = 300)
chr "changing moving in a circle i can see your face in all of my dreams smiling laughing from the shadows when i hear your voice i know what it means i know it does not matter just how hard i try you are all the reason for my life disillusion disillusion all you left "| __truncated__
SENTIMENT ANALYSIS OF LYRICS Let us perform sentiment analysis on the lyrics. There are various types of sentiment lexicons that can be used. Lets us have a look on them.
library(tidytext)
library(tidyr)
get_sentiments("afinn")
get_sentiments("bing")
get_sentiments("nrc")
get_sentiments("loughran")
nrc seems to have large number of words and their sentiments compared to other two.
nrc_sentiment <- get_sentiments("nrc")
unique(nrc_sentiment$sentiment)
[1] "trust" "fear" "negative" "sadness" "anger" "surprise" "positive"
[8] "disgust" "joy" "anticipation"
Let us find the sentiments of each lyrics based on each NRC sentiments.
lyrics_words <- select(lyrics, c("artist", "text"))
lyrics_words <- lyrics_words %>% unnest_tokens(word, text)
head(lyrics_words)
Let’s see words that depict “joy”
joy <- lyrics_words %>%
inner_join(get_sentiments("nrc") %>%
filter(sentiment == "joy"))
Joining, by = "word"
joy <- as.data.frame(sort(table(joy$word)))
columns_sentiment <- c("word", "Freq")
colnames(joy) <- columns_sentiment
tail(joy, 10)
Similarly, let’s see other words that represents other 9 sentiments.
trust <- lyrics_words %>%
inner_join(get_sentiments("nrc") %>%
filter(sentiment == "trust"))
Joining, by = "word"
trust <- as.data.frame(sort(table(trust$word)))
colnames(trust) <- columns_sentiment
tail(trust, 10)
fear <- lyrics_words %>%
inner_join(get_sentiments("nrc") %>%
filter(sentiment == "fear"))
Joining, by = "word"
fear <- as.data.frame(sort(table(fear$word)))
colnames(fear) <- columns_sentiment
sadness <- lyrics_words %>%
inner_join(get_sentiments("nrc") %>%
filter(sentiment == "sadness"))
Joining, by = "word"
sadness <- as.data.frame(sort(table(sadness$word)))
colnames(sadness) <- columns_sentiment
anger <- lyrics_words %>%
inner_join(get_sentiments("nrc") %>%
filter(sentiment == "anger"))
Joining, by = "word"
anger <- as.data.frame(sort(table(anger$word)))
colnames(anger) <- columns_sentiment
surprise <- lyrics_words %>%
inner_join(get_sentiments("nrc") %>%
filter(sentiment == "surprise"))
Joining, by = "word"
surprise <- as.data.frame(sort(table(surprise$word)))
colnames(surprise) <- columns_sentiment
disgust <- lyrics_words %>%
inner_join(get_sentiments("nrc") %>%
filter(sentiment == "disgust"))
Joining, by = "word"
disgust <- as.data.frame(sort(table(disgust$word)))
colnames(disgust) <- columns_sentiment
anticipation <- lyrics_words %>%
inner_join(get_sentiments("nrc") %>%
filter(sentiment == "anticipation"))
Joining, by = "word"
anticipation <- as.data.frame(sort(table(anticipation$word)))
colnames(anticipation) <- columns_sentiment
Let’s plot the word occurences for each sentiment (except positive and negative)

Let us check top words that depicts “positive” and “negative” sentiments in NRC Sentiment category.
Joining, by = "word"
Joining, by = "word"

Let us check top words that depicts “positive” and “negative” sentiments in bing Sentiment category.
Joining, by = "word"
Joining, by = "word"
Joining, by = "word"
Joining, by = "word"

It can be seen that positive and negative words are different for all three lexicons.
LS0tCnRpdGxlOiAiTHlyaWNzIEFuYWx5c2lzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpMZXRzIHVzIHJlYWQgdGhlIGZpbGUuCgpgYGB7cn0KbGlicmFyeShyZWFkcikKbHlyaWNzIDwtIHJlYWRfY3N2KCJzb25nZGF0YS5jc3YiKQpoZWFkKGx5cmljcykKYGBgCgpMZXRzIHVzIGV4YW1pbmUgdGhlIGRpbWVuc2lvbiBvZiB0aGUgbHlyaWNzIGRhdGFmcmFtZS4KCmBgYHtyfQpkaW0obHlyaWNzKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpnbGltcHNlKGx5cmljcykKYGBgCgpBbmFseXNpcyBvZiA1NTAwMCsgbHlyaWNzIGRhdGEKLSBOdW1iZXIgb2YgYXJ0aXN0cwotIFdoaWNoIGFydGlzdCBoYXMgaGlnaGVzdCBhbmQgbG93ZXN0IG51bWJlciBvZiBzb25ncyAKLSBEaXN0cmlidXRpb24gb2Ygc29uZ3Mgb2YgYWxsIGFydGlzdHMgaW4gdGhlIGRhdGFzZXQKLSBEaXN0cmlidXRpb24gb2YgbHlyaWNzIGxlbmd0aAotIFdoaWNoIHNvbmcgbHlyaWNzIGhhcyBtYXhpbXVtIG51bWJlciBvZiB3b3JkcwotIFdoaWNoIHNvbmcgbHlyaWNzIGhhcyBtaW5pbXVtIG51bWJlciBvZiB3b3JkcwotIERpc3RyaWJ1dGlvbiBvZiB3b3JkcyBjb3VudCBpbiB0aXRsZQotIFdoaWNoIHNvbmdzIHRpdGxlIGhhcyBtYXhpbXVtIG51bWJlciBvZiB3b3JkcyAKLSBXaGljaCBzb25ncyB0aXRsZSBoYXMgbWluaW11bSBudW1iZXIgb2Ygd29yZHMKLSBXb3JkQ2xvdWRzIG9mIHRpdGxlcyB3aXRoIG1pbmltdW0gYW5kIG1heGltdW0gbGVuZ3RocwotIElzIHRoZXJlIGEgcmVsYXRpb24gYmV0d2VlbiB0aXRsZSBsZW5ndGggYW5kIHNvbmcgbGVuZ3RoPwoKCi0gU2VudGltZW50cyBvZiB0aGUgc29uZ3MgKE5SQywgQmluZykKLSBXaGljaCB3b3JkcyBhcmUgbW9zdCBvY2N1cmluZyBpbiB0aGUgbHlyaWNzIG9mIHRoZSBzb25ncwotIElzIHRoZXJlIGEgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgd29yZHMgaW4gdGhlIHNvbmdzIG9mIHNhbWUgYXJ0aXN0cz8KLSBXb3JkY2xvdWQgb2YgbW9zdCBwb3B1bGFyIHdvcmRzIGluIHRoZSBzb25ncwotIFRvcCB3b3JkcyB1c2VkIGJ5IGFuIGFydGlzdCBpbiBoaXMvaGVyIHNvbmdzCi0gQXJlIHRoZXJlIHNvbWUgY29tbW9uIFJ5dGhtaWMgd29yZHMgdGhhdCByZXBlYXRzIGFnYWluIGFuZCBhZ2Fpbj8KCgpMZXQncyBzdGFydCB3aXRoIGZpbmRpbmcgb3V0IGhvdyBtYW55IGFydGlzdHMgYXJlIGxpc3RlZCBpbiB0aGUgZGF0YS4gQWxzbywgaG93IG1hbnkgc29uZ3MgZWFjaCBhcnRpc3QgaGFzLgoKYGBge3J9CmFydGlzdDwtIGFzLmRhdGEuZnJhbWUodGFibGUoYXMuZGF0YS5mcmFtZShseXJpY3MkYXJ0aXN0KSkpCmNvbG5hbWVzKGFydGlzdCkgPC0gYygiYXJ0aXN0IiwgIk51bV9vZl9zb25ncyIpCmhlYWQoYXJ0aXN0KQpgYGAKCkxldCdzIHNlZSB0aGUgd2hpY2ggYXJ0aXN0IGhhcyBtb3N0IGFuZCBsZWFzdCBudW1iZXIgb2Ygc29uZ3MgaW4gdGhlIGRhdGFzZXQuCgpgYGB7cn0KbW9zdF9zb25ncyA8LSBhcnJhbmdlKGFydGlzdCwgZGVzYyhOdW1fb2Zfc29uZ3MpKQptb3N0X3NvbmdzCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9MywgZWNobz1GQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KFJtaXNjKQp0aWx0X3RoZW1lIDwtIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpCnAxIDwtIGdncGxvdChkYXRhID0gaGVhZChtb3N0X3NvbmdzLDEwKSwgYWVzKGFydGlzdCwgTnVtX29mX3NvbmdzLCBmaWxsID0gTnVtX29mX3NvbmdzKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPU51bV9vZl9zb25ncyksIHZqdXN0PTEuNiwgY29sb3I9IndoaXRlIiwgc2l6ZT0zKSArCiAgICAgIGdndGl0bGUoIkFydGlzdHMgd2l0aCBtb3N0IG51bWJlciBvZiBzb25ncyIpICsKICAgICAgdGlsdF90aGVtZQpwMQpgYGAKCmBgYHtyfQpsZWFzdF9zb25ncyA8LSB0YWlsKG1vc3Rfc29uZ3MsIDE1KQpwMiA8LSBnZ3Bsb3QoZGF0YSA9IGxlYXN0X3NvbmdzLCBhZXMoYXJ0aXN0LCBOdW1fb2Zfc29uZ3MsIGZpbGwgPSBOdW1fb2Zfc29uZ3MpKSArCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9TnVtX29mX3NvbmdzKSwgdmp1c3Q9MS42LCBjb2xvcj0id2hpdGUiLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiQXJ0aXN0cyB3aXRoIGxlYXN0IG51bWJlciBvZiBzb25ncyIpICsKICAgICAgdGlsdF90aGVtZQpwMgpgYGAKCkxldCdzIGNoZWNrIHRoZSBkaXN0cmlidXRpb24gb2Ygc29uZ3MgZm9yIGFsbCBhcnRpc3RzLgoKYGBge3J9CnAzIDwtIGdncGxvdChhcnRpc3QsIGFlcyh4PU51bV9vZl9zb25ncykpICsgCiBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiksIGNvbG91cj0iYmxhY2siLCBmaWxsPSJ3aGl0ZSIpKwogZ2VvbV9kZW5zaXR5KGFscGhhPS4yLCBmaWxsPSJyZWQiKQpwMwpgYGAKCkxldCdzIGFuYWx5emUgdGhlIG51bWJlciBvZiB3b3JkcyBpbiBlYWNoIHNvbmcgYW5kIGl0cyBkaXN0cmlidXRpb24uCgpgYGB7cn0KbGlicmFyeShzdHJpbmdyKQpjb3VudF93b3JkcyA8LSBmdW5jdGlvbih2ZWMpewogIHJldHVybiAobGVuZ3RoKHVubGlzdCgoc3RyX2V4dHJhY3RfYWxsKHRvbG93ZXIodmVjKSwgJ1xcdysnKSkpKSkKfQpseXJpY3Mkd29yZF9jb3VudCA8LSBzYXBwbHkobHlyaWNzJHRleHQsIGNvdW50X3dvcmRzKQpoZWFkKGx5cmljcyR3b3JkX2NvdW50KQpgYGAKCmBgYHtyfQpwNCA8LSBnZ3Bsb3QobHlyaWNzLCBhZXMoeD13b3JkX2NvdW50KSkgKyAKIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uKSwgY29sb3VyPSJibGFjayIsIGZpbGw9IndoaXRlIikrCiBnZW9tX2RlbnNpdHkoYWxwaGE9LjIsIGZpbGw9InJlZCIpCnA0CmBgYAoKTGV0J3MgYW5hbHl6ZSB0aGUgdGl0bGUgb2YgdGhlIHNvbmdzLCB0aGVpciB3b3JkY291bnQgYW5kIHRoZWlyIGRpc3RyaWJ1dGlvbgoKYGBge3J9Cmx5cmljcyR0aXRsZV93b3JkX2NvdW50IDwtIHNhcHBseShseXJpY3Mkc29uZywgY291bnRfd29yZHMpCmhlYWQobHlyaWNzJHRpdGxlX3dvcmRfY291bnQpCmBgYAoKTGV0J3MgY2hlY2sgb3V0IHRoZSBzb25ncyB0aGF0IGFyZSBsb25nZXN0IGFuZCBzaG9ydGVzdC4KCmBgYHtyfQpsb25nZXN0X3NvbmcgPC0gYXJyYW5nZShseXJpY3MsIGRlc2Mod29yZF9jb3VudCkpCmxvbmdlc3Rfc29uZyA8LSBoZWFkKGxvbmdlc3Rfc29uZywgMTApCnNob3J0ZXN0X3NvbmcgPC0gYXJyYW5nZShseXJpY3MsIHdvcmRfY291bnQpCnNob3J0ZXN0X3NvbmcgPC0gaGVhZChzaG9ydGVzdF9zb25nLCAxMCkKbG9uZ2VzdF9zb25nCnNob3J0ZXN0X3NvbmcKYGBgCgoKCmBgYHtyfQpwNSA8LSBnZ3Bsb3QoZGF0YSA9IGxvbmdlc3Rfc29uZywgYWVzKHNvbmcsIHdvcmRfY291bnQsIGZpbGwgPSB0aXRsZV93b3JkX2NvdW50KSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPXRpdGxlX3dvcmRfY291bnQpLCB2anVzdD0xLjYsIGNvbG9yPSJ3aGl0ZSIsIHNpemU9MykgKwogICAgICBnZ3RpdGxlKCJMb25nZXN0IFNvbmdzIikgKwogICAgICB0aWx0X3RoZW1lCnA2IDwtIGdncGxvdChkYXRhID0gc2hvcnRlc3Rfc29uZywgYWVzKHNvbmcsIHdvcmRfY291bnQsIGZpbGwgPSB0aXRsZV93b3JkX2NvdW50KSkgKwogICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSB0aXRsZV93b3JkX2NvdW50KSwgdmp1c3QgPSAxLjYsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDMpICsKICAgICAgZ2d0aXRsZSgiU2hvcnRlc3QgU29uZ3MiKSArCiAgICAgIHRpbHRfdGhlbWUKbXVsdGlwbG90KHA1LCBwNiwgY29scz0yKQpgYGAKCgoKCmBgYHtyfQpwNyA8LSBnZ3Bsb3QobHlyaWNzLCBhZXMoeD10aXRsZV93b3JkX2NvdW50KSkgKyAKIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uKSwgY29sb3VyPSJibGFjayIsIGZpbGw9IndoaXRlIiwgYmlud2lkdGggPSAxLCBiaW5zID0gMSkrCiBnZW9tX2RlbnNpdHkoYWxwaGE9LjIsIGZpbGw9InJlZCIpCnA3CmBgYAoKV29yZENsb3VkIG9mIHBvcHVsYXIgd29yZHMgZnJvbSBzb25nIHRpdGxlcwoKYGBge3J9CmxpYnJhcnkod29yZGNsb3VkKQpsaWJyYXJ5KFNub3diYWxsQykKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkodG0pCnRleHRzIDwtIGx5cmljcyRzb25nCiN0ZXh0cyA8LSBpY29udih0ZXh0cywgdG8gPSAidXRmLTgiKQpjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0cykpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBQbGFpblRleHREb2N1bWVudCkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygnZW5nbGlzaCcpKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgc3RlbURvY3VtZW50KQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlV29yZHMsIGMoImFuZCIsICJ0aGlzIiwgInRoZXJlIikpIApjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZShjb3JwdXMpKQpkdG0gPC0gVGVybURvY3VtZW50TWF0cml4KGNvcnB1cykKbSA8LSBhcy5tYXRyaXgoZHRtKQp2IDwtIHNvcnQocm93U3VtcyhtKSxkZWNyZWFzaW5nPVRSVUUpCmQgPC0gZGF0YS5mcmFtZSh3b3JkID0gbmFtZXModiksZnJlcT12KQpoZWFkKGQsIDEwKQpkIDwtIGRbLXdoaWNoKGQkd29yZCAlaW4lIGMoImFuZCIsInRoaXMiLCJ0aGF0IikpLF0Kc2V0LnNlZWQoMTIzNCkKd29yZGNsb3VkKHdvcmRzID0gZCR3b3JkLCBmcmVxID0gZCRmcmVxLCBtaW4uZnJlcSA9IDEsCiAgICAgICAgICBtYXgud29yZHM9MjAwLCByYW5kb20ub3JkZXI9RkFMU0UsIHJvdC5wZXI9MC4zNSwgCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg4LCAiRGFyazIiKSkKYGBgCgpUaGVyZSBhcmUgbWFueSBzb25nIHRpdGxlcyB0aGF0IGFyZSBvZiBsZW5ndGggMSwgMiBhbmQgMy4gQnV0IHN1cnByaXNpbmdseSwgdGhlcmUgYXJlIHRpdGxlcyBvZiBsZW5ndGggbW9yZSB0aGFuIDEzIHRvby4gTGV0J3MgY2hlY2sgdGhlbSBvdXQuCgpgYGB7cn0KbG9uZ2VzdF90aXRsZSA8LSBzdWJzZXQobHlyaWNzLCBseXJpY3MkdGl0bGVfd29yZF9jb3VudCA+IDEzKQpsb25nZXN0X3RpdGxlCnNob3J0ZXN0X3RpdGxlIDwtIHN1YnNldChseXJpY3MsIGx5cmljcyR0aXRsZV93b3JkX2NvdW50ID09IDEpCnNob3J0ZXN0X3RpdGxlCmBgYAoKVGhlcmUgYXJlIDggc29uZ3Mgd2l0aCB0aXRsZSBsZW5ndGggbW9yZSB0aGFuIDEzIGFuZCA4MzQyIHNvbmdzIHdpdGggc2luZ2xlIHdvcmQgdGl0bGUuIExldCdzIHNlZSB3b3JkIGNsb3VkIG9mIHNpbmdsZSB3b3JkIHRpdGxlcyBhbmQgbG9uZ2VzdCB0aXRsZXMKCmBgYHtyfQp0ZXh0cyA8LSBsb25nZXN0X3RpdGxlJHNvbmcKY29ycHVzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UodGV4dHMpKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgUGxhaW5UZXh0RG9jdW1lbnQpCmNvcnB1cyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKGNvcnB1cykpCmR0bSA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoY29ycHVzKQptIDwtIGFzLm1hdHJpeChkdG0pCnYgPC0gc29ydChyb3dTdW1zKG0pLGRlY3JlYXNpbmc9VFJVRSkKZCA8LSBkYXRhLmZyYW1lKHdvcmQgPSBuYW1lcyh2KSxmcmVxPXYpCmhlYWQoZCwgMTApCnNldC5zZWVkKDEyMzQpCndvcmRjbG91ZCh3b3JkcyA9IGQkd29yZCwgZnJlcSA9IGQkZnJlcSwgbWluLmZyZXEgPSAxLHNjYWxlPWMoMiwwLjUpLAogICAgICAgICAgbWF4LndvcmRzPTEwMCwgcmFuZG9tLm9yZGVyPUZBTFNFLCByb3QucGVyPTAuMzUsIAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOCwgIkRhcmsyIikpCmBgYAoKYGBge3J9CnRleHRzIDwtIHNob3J0ZXN0X3RpdGxlJHNvbmcKY29ycHVzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UodGV4dHMpKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgUGxhaW5UZXh0RG9jdW1lbnQpCmNvcnB1cyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKGNvcnB1cykpCmR0bSA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoY29ycHVzKQptIDwtIGFzLm1hdHJpeChkdG0pCnYgPC0gc29ydChyb3dTdW1zKG0pLGRlY3JlYXNpbmc9VFJVRSkKZCA8LSBkYXRhLmZyYW1lKHdvcmQgPSBuYW1lcyh2KSxmcmVxPXYpCmhlYWQoZCwgMTApCnNldC5zZWVkKDEyMzQpCndvcmRjbG91ZCh3b3JkcyA9IGQkd29yZCwgZnJlcSA9IGQkZnJlcSwgbWluLmZyZXEgPSAxLHNjYWxlPWMoMiwwLjUpLAogICAgICAgICAgbWF4LndvcmRzPTEwMCwgcmFuZG9tLm9yZGVyPUZBTFNFLCByb3QucGVyPTAuMzUsIAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOCwgIkRhcmsyIikpCmBgYAoKQW4gaW50ZXJlc3RpbmcgcXVlc3RpbiB3b3VsZCBiZSBpcyB0aGVyZSByZWxhdGlvbiBiZXR3ZWVuIGxlbmd0aCBvZiB0aXRsZSBhbmQgc29uZ3M/IE1vc3QgcHJvYmFibHkgbm93LCBidXQgbGV0J3MgY2hlY2sgb3V0LgoKYGBge3J9CnA4IDwtIGdncGxvdChseXJpY3MsIGFlcyh4PWZhY3Rvcih0aXRsZV93b3JkX2NvdW50KSwgeT13b3JkX2NvdW50LCBmaWxsID0gZmFjdG9yKHRpdGxlX3dvcmRfY291bnQpKSkgKyAKICBnZW9tX2JveHBsb3QoKSAKcDggCmBgYAoKYGBge3J9CmNvcihseXJpY3MkdGl0bGVfd29yZF9jb3VudCwgbHlyaWNzJHdvcmRfY291bnQpCmBgYAogQXMgZXhwZWN0ZWQsIHRoZXJlIGlzIG5vIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlc2UgdHdvIHF1YW50aXRpdGVzLgogCiBMZXQgdXMgZml4IHRoZSBjb250cmFjdGVkIHdvcmRzIHRvIHRoZWlyIGZ1bGwgZm9ybXMgZmlyc3QuCgpgYGB7cn0KIyBmdW5jdGlvbiB0byBleHBhbmQgY29udHJhY3Rpb25zIGluIGFuIEVuZ2xpc2gtbGFuZ3VhZ2Ugc291cmNlCmZpeC5jb250cmFjdGlvbnMgPC0gZnVuY3Rpb24oZG9jKSB7CiAgIyAid29uJ3QiIGlzIGEgc3BlY2lhbCBjYXNlIGFzIGl0IGRvZXMgbm90IGV4cGFuZCB0byAid28gbm90IgogIGRvYyA8LSBnc3ViKCJ3b24ndCIsICJ3aWxsIG5vdCIsIGRvYykKICBkb2MgPC0gZ3N1YigiY2FuJ3QiLCAiY2FuIG5vdCIsIGRvYykKICBkb2MgPC0gZ3N1Yigibid0IiwgIiBub3QiLCBkb2MpCiAgZG9jIDwtIGdzdWIoIidsbCIsICIgd2lsbCIsIGRvYykKICBkb2MgPC0gZ3N1YigiJ3JlIiwgIiBhcmUiLCBkb2MpCiAgZG9jIDwtIGdzdWIoIid2ZSIsICIgaGF2ZSIsIGRvYykKICBkb2MgPC0gZ3N1YigiJ20iLCAiIGFtIiwgZG9jKQogIGRvYyA8LSBnc3ViKCInZCIsICIgd291bGQiLCBkb2MpCiAgIyAncyBjb3VsZCBiZSAnaXMnIG9yIGNvdWxkIGJlIHBvc3Nlc3NpdmU6IGl0IGhhcyBubyBleHBhbnNpb24KICBkb2MgPC0gZ3N1YigiJ3MiLCAiIiwgZG9jKQogIHJldHVybihkb2MpCn0KCiMgZml4IChleHBhbmQpIGNvbnRyYWN0aW9ucwpseXJpY3MkdGV4dCA8LSBzYXBwbHkobHlyaWNzJHRleHQsIGZpeC5jb250cmFjdGlvbnMpCmBgYAogCiBSZW1vdmUgc3BlY2lhbCBjaGFyYWN0ZXJzIGZyb20gbHlyaWNzCmBgYHtyfQojIGZ1bmN0aW9uIHRvIHJlbW92ZSBzcGVjaWFsIGNoYXJhY3RlcnMKcmVtb3ZlU3BlY2lhbENoYXJzIDwtIGZ1bmN0aW9uKHgpIGdzdWIoIlteYS16QS1aMC05IF0iLCAiICIsIHgpCiMgcmVtb3ZlIHNwZWNpYWwgY2hhcmFjdGVycwpseXJpY3MkdGV4dCA8LSBzYXBwbHkobHlyaWNzJHRleHQsIHJlbW92ZVNwZWNpYWxDaGFycykKYGBgCgpDb252ZXJ0IGFsbCBseXJpY3MgdGV4dCB0byBsb3dlciBjYXNlCmBgYHtyfQojIGNvbnZlcnQgZXZlcnl0aGluZyB0byBsb3dlciBjYXNlCmx5cmljcyR0ZXh0IDwtIHNhcHBseShseXJpY3MkdGV4dCwgdG9sb3dlcikKYGBgCgpMZXQncyBjaGVjayB0aGUgc3RydWN0dXJlIG9mIG9uZSBseXJpY3MgdG8gc2VlIHRoZSBjaGFuZ2VzLgpgYGB7cn0Kc3RyKGx5cmljc1sxMywgXSR0ZXh0LCBuY2hhci5tYXggPSAzMDApCmBgYAogCiBTRU5USU1FTlQgQU5BTFlTSVMgT0YgTFlSSUNTCiBMZXQgdXMgcGVyZm9ybSBzZW50aW1lbnQgYW5hbHlzaXMgb24gdGhlIGx5cmljcy4gVGhlcmUgYXJlIHZhcmlvdXMgdHlwZXMgb2Ygc2VudGltZW50IGxleGljb25zIHRoYXQgY2FuIGJlIHVzZWQuIExldHMgdXMgaGF2ZSBhIGxvb2sgb24gdGhlbS4KYGBge3J9CmxpYnJhcnkodGlkeXRleHQpCmxpYnJhcnkodGlkeXIpCmdldF9zZW50aW1lbnRzKCJhZmlubiIpCmdldF9zZW50aW1lbnRzKCJiaW5nIikKZ2V0X3NlbnRpbWVudHMoIm5yYyIpCmdldF9zZW50aW1lbnRzKCJsb3VnaHJhbiIpCmBgYAoKbnJjIHNlZW1zIHRvIGhhdmUgbGFyZ2UgbnVtYmVyIG9mIHdvcmRzIGFuZCB0aGVpciBzZW50aW1lbnRzIGNvbXBhcmVkIHRvIG90aGVyIHR3by4KCmBgYHtyfQpucmNfc2VudGltZW50IDwtIGdldF9zZW50aW1lbnRzKCJucmMiKQp1bmlxdWUobnJjX3NlbnRpbWVudCRzZW50aW1lbnQpCmBgYAoKTGV0IHVzIGZpbmQgdGhlIHNlbnRpbWVudHMgb2YgZWFjaCBseXJpY3MgYmFzZWQgb24gZWFjaCBOUkMgc2VudGltZW50cy4KCmBgYHtyfQpseXJpY3Nfd29yZHMgPC0gc2VsZWN0KGx5cmljcywgYygiYXJ0aXN0IiwgInRleHQiKSkKbHlyaWNzX3dvcmRzIDwtIGx5cmljc193b3JkcyAlPiUgdW5uZXN0X3Rva2Vucyh3b3JkLCB0ZXh0KQpoZWFkKGx5cmljc193b3JkcykKZGltKGx5cmljc193b3JkcykKYGBgCgpMZXQncyBzZWUgd29yZHMgdGhhdCBkZXBpY3QgImpveSIKYGBge3J9CmpveSA8LSBseXJpY3Nfd29yZHMgJT4lCiAgaW5uZXJfam9pbihnZXRfc2VudGltZW50cygibnJjIikgJT4lIAogIGZpbHRlcihzZW50aW1lbnQgPT0gImpveSIpKSAKam95IDwtIGFzLmRhdGEuZnJhbWUoc29ydCh0YWJsZShqb3kkd29yZCkpKQpjb2x1bW5zX3NlbnRpbWVudCA8LSBjKCJ3b3JkIiwgIkZyZXEiKQpjb2xuYW1lcyhqb3kpIDwtIGNvbHVtbnNfc2VudGltZW50CnRhaWwoam95LCAxMCkKCmBgYAoKU2ltaWxhcmx5LCBsZXQncyBzZWUgb3RoZXIgd29yZHMgdGhhdCByZXByZXNlbnRzIG90aGVyIDkgc2VudGltZW50cy4KCmBgYHtyfQp0cnVzdCA8LSBseXJpY3Nfd29yZHMgJT4lCiAgaW5uZXJfam9pbihnZXRfc2VudGltZW50cygibnJjIikgJT4lIAogIGZpbHRlcihzZW50aW1lbnQgPT0gInRydXN0IikpIAp0cnVzdCA8LSBhcy5kYXRhLmZyYW1lKHNvcnQodGFibGUodHJ1c3Qkd29yZCkpKQpjb2xuYW1lcyh0cnVzdCkgPC0gY29sdW1uc19zZW50aW1lbnQKdGFpbCh0cnVzdCwgMTApCmBgYAoKYGBge3J9CmZlYXIgPC0gbHlyaWNzX3dvcmRzICU+JQogIGlubmVyX2pvaW4oZ2V0X3NlbnRpbWVudHMoIm5yYyIpICU+JSAKICBmaWx0ZXIoc2VudGltZW50ID09ICJmZWFyIikpIApmZWFyIDwtIGFzLmRhdGEuZnJhbWUoc29ydCh0YWJsZShmZWFyJHdvcmQpKSkKY29sbmFtZXMoZmVhcikgPC0gY29sdW1uc19zZW50aW1lbnQKCnNhZG5lc3MgPC0gbHlyaWNzX3dvcmRzICU+JQogIGlubmVyX2pvaW4oZ2V0X3NlbnRpbWVudHMoIm5yYyIpICU+JSAKICBmaWx0ZXIoc2VudGltZW50ID09ICJzYWRuZXNzIikpIApzYWRuZXNzIDwtIGFzLmRhdGEuZnJhbWUoc29ydCh0YWJsZShzYWRuZXNzJHdvcmQpKSkKY29sbmFtZXMoc2FkbmVzcykgPC0gY29sdW1uc19zZW50aW1lbnQKCmFuZ2VyIDwtIGx5cmljc193b3JkcyAlPiUKICBpbm5lcl9qb2luKGdldF9zZW50aW1lbnRzKCJucmMiKSAlPiUgCiAgZmlsdGVyKHNlbnRpbWVudCA9PSAiYW5nZXIiKSkgCmFuZ2VyIDwtIGFzLmRhdGEuZnJhbWUoc29ydCh0YWJsZShhbmdlciR3b3JkKSkpCmNvbG5hbWVzKGFuZ2VyKSA8LSBjb2x1bW5zX3NlbnRpbWVudAoKc3VycHJpc2UgPC0gbHlyaWNzX3dvcmRzICU+JQogIGlubmVyX2pvaW4oZ2V0X3NlbnRpbWVudHMoIm5yYyIpICU+JSAKICBmaWx0ZXIoc2VudGltZW50ID09ICJzdXJwcmlzZSIpKSAKc3VycHJpc2UgPC0gYXMuZGF0YS5mcmFtZShzb3J0KHRhYmxlKHN1cnByaXNlJHdvcmQpKSkKY29sbmFtZXMoc3VycHJpc2UpIDwtIGNvbHVtbnNfc2VudGltZW50CgpkaXNndXN0IDwtIGx5cmljc193b3JkcyAlPiUKICBpbm5lcl9qb2luKGdldF9zZW50aW1lbnRzKCJucmMiKSAlPiUgCiAgZmlsdGVyKHNlbnRpbWVudCA9PSAiZGlzZ3VzdCIpKSAKZGlzZ3VzdCA8LSBhcy5kYXRhLmZyYW1lKHNvcnQodGFibGUoZGlzZ3VzdCR3b3JkKSkpCmNvbG5hbWVzKGRpc2d1c3QpIDwtIGNvbHVtbnNfc2VudGltZW50CgphbnRpY2lwYXRpb24gPC0gbHlyaWNzX3dvcmRzICU+JQogIGlubmVyX2pvaW4oZ2V0X3NlbnRpbWVudHMoIm5yYyIpICU+JSAKICBmaWx0ZXIoc2VudGltZW50ID09ICJhbnRpY2lwYXRpb24iKSkgCmFudGljaXBhdGlvbiA8LSBhcy5kYXRhLmZyYW1lKHNvcnQodGFibGUoYW50aWNpcGF0aW9uJHdvcmQpKSkKY29sbmFtZXMoYW50aWNpcGF0aW9uKSA8LSBjb2x1bW5zX3NlbnRpbWVudApgYGAKCkxldCdzIHBsb3QgdGhlIHdvcmQgb2NjdXJlbmNlcyBmb3IgZWFjaCBzZW50aW1lbnQgKGV4Y2VwdCBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUpCgpgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD00LCBlY2hvPUZBTFNFfQpwOSA8LSBnZ3Bsb3QoZGF0YSA9IHRhaWwoam95LCAxMCksIGFlcyh3b3JkLCBGcmVxLCBmaWxsID0gd29yZCkpICsKICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gRnJlcSksIHZqdXN0ID0gMS42LCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzKSArCiAgICAgIGdndGl0bGUoIkpveSIpICsKICAgICAgZ3VpZGVzKGZpbGw9RkFMU0UpICsKICAgICAgdGlsdF90aGVtZQpwMTAgPC0gZ2dwbG90KGRhdGEgPSB0YWlsKHRydXN0LCAxMCksIGFlcyh3b3JkLCBGcmVxLCBmaWxsID0gd29yZCkpICsKICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gRnJlcSksIHZqdXN0ID0gMS42LCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzKSArCiAgICAgIGdndGl0bGUoIlRydXN0IikgKwogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICB0aWx0X3RoZW1lCnAxMSA8LSBnZ3Bsb3QoZGF0YSA9IHRhaWwoZmVhciwgMTApLCBhZXMod29yZCwgRnJlcSwgZmlsbCA9IHdvcmQpKSArCiAgICAgIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZXEpLCB2anVzdCA9IDEuNiwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKwogICAgICBnZ3RpdGxlKCJGZWFyIikgKwogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICB0aWx0X3RoZW1lCnAxMiA8LSBnZ3Bsb3QoZGF0YSA9IHRhaWwoc2FkbmVzcywgMTApLCBhZXMod29yZCwgRnJlcSwgZmlsbCA9IHdvcmQpKSArCiAgICAgIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZXEpLCB2anVzdCA9IDEuNiwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKwogICAgICBnZ3RpdGxlKCJTYWRuZXNzIikgKwogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICB0aWx0X3RoZW1lCnAxMyA8LSBnZ3Bsb3QoZGF0YSA9IHRhaWwoYW5nZXIsIDEwKSwgYWVzKHdvcmQsIEZyZXEsIGZpbGwgPSB3b3JkKSkgKwogICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBGcmVxKSwgdmp1c3QgPSAxLjYsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDMpICsKICAgICAgZ2d0aXRsZSgiQW5nZXIiKSArCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIHRpbHRfdGhlbWUKcDE0IDwtIGdncGxvdChkYXRhID0gdGFpbChzdXJwcmlzZSwgMTApLCBhZXMod29yZCwgRnJlcSwgZmlsbCA9IHdvcmQpKSArCiAgICAgIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZXEpLCB2anVzdCA9IDEuNiwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKwogICAgICBnZ3RpdGxlKCJTdXJwcmlzZSIpICsKICAgICAgZ3VpZGVzKGZpbGw9RkFMU0UpICsKICAgICAgdGlsdF90aGVtZQpwMTUgPC0gZ2dwbG90KGRhdGEgPSB0YWlsKGRpc2d1c3QsIDEwKSwgYWVzKHdvcmQsIEZyZXEsIGZpbGwgPSB3b3JkKSkgKwogICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBGcmVxKSwgdmp1c3QgPSAxLjYsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDMpICsKICAgICAgZ2d0aXRsZSgiRGlzZ3VzdCIpICsKICAgICAgZ3VpZGVzKGZpbGw9RkFMU0UpICsKICAgICAgdGlsdF90aGVtZQpwMTYgPC0gZ2dwbG90KGRhdGEgPSB0YWlsKGFudGljaXBhdGlvbiwgMTApLCBhZXMod29yZCwgRnJlcSwgZmlsbCA9IHdvcmQpKSArCiAgICAgIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZXEpLCB2anVzdCA9IDEuNiwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKwogICAgICBnZ3RpdGxlKCJBbnRpY2lwYXRpb24iKSArCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIHRpbHRfdGhlbWUKCm11bHRpcGxvdChwOSwgcDEwLCBwMTEsIHAxMiwgcDEzLCBwMTQsIHAxNSwgcDE2LCBsYXlvdXQgPSBtYXRyaXgoYygxLDIsMyw0LDUsNiw3LDgpLCBucm93PTIsIGJ5cm93PVRSVUUpKQoKCmBgYAoKTGV0IHVzIGNoZWNrIHRvcCB3b3JkcyB0aGF0IGRlcGljdHMgInBvc2l0aXZlIiBhbmQgIm5lZ2F0aXZlIiBzZW50aW1lbnRzIGluIE5SQyBTZW50aW1lbnQgY2F0ZWdvcnkuCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD0yLCBlY2hvPUZBTFNFfQpwb3MgPC0gbHlyaWNzX3dvcmRzICU+JQogIGlubmVyX2pvaW4oZ2V0X3NlbnRpbWVudHMoIm5yYyIpICU+JSAKICBmaWx0ZXIoc2VudGltZW50ID09ICJwb3NpdGl2ZSIpKSAKcG9zIDwtIGFzLmRhdGEuZnJhbWUoc29ydCh0YWJsZShwb3Mkd29yZCkpKQpjb2xuYW1lcyhwb3MpIDwtIGNvbHVtbnNfc2VudGltZW50CgpuZWcgPC0gbHlyaWNzX3dvcmRzICU+JQogIGlubmVyX2pvaW4oZ2V0X3NlbnRpbWVudHMoIm5yYyIpICU+JSAKICBmaWx0ZXIoc2VudGltZW50ID09ICJuZWdhdGl2ZSIpKSAKbmVnIDwtIGFzLmRhdGEuZnJhbWUoc29ydCh0YWJsZShuZWckd29yZCkpKQpjb2xuYW1lcyhuZWcpIDwtIGNvbHVtbnNfc2VudGltZW50CgpwMTcgPC0gZ2dwbG90KGRhdGEgPSB0YWlsKHBvcywgMjApLCBhZXMod29yZCwgRnJlcSwgZmlsbCA9IHdvcmQpKSArCiAgICAgIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZXEpLCB2anVzdCA9IDEuNiwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMywgYW5nbGU9OTApICsKICAgICAgZ2d0aXRsZSgiUG9zaXRpdmUgKE5SQykiKSArCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIHRpbHRfdGhlbWUKcDE4IDwtIGdncGxvdChkYXRhID0gdGFpbChuZWcsIDIwKSwgYWVzKHdvcmQsIEZyZXEsIGZpbGwgPSB3b3JkKSkgKwogICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBGcmVxKSwgdmp1c3QgPSAxLjYsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMsIGFuZ2xlPTkwKSArCiAgICAgIGdndGl0bGUoIk5lZ2F0aXZlIChOUkMpIikgKwogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICB0aWx0X3RoZW1lCm11bHRpcGxvdChwMTcsIHAxOCwgY29scz0yKQpgYGAKCkxldCB1cyBjaGVjayB0b3Agd29yZHMgdGhhdCBkZXBpY3RzICJwb3NpdGl2ZSIgYW5kICJuZWdhdGl2ZSIgc2VudGltZW50cyBpbiBiaW5nIFNlbnRpbWVudCBjYXRlZ29yeS4KCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01LCBlY2hvPUZBTFNFfQpwb3NfYiA8LSBseXJpY3Nfd29yZHMgJT4lCiAgaW5uZXJfam9pbihnZXRfc2VudGltZW50cygiYmluZyIpICU+JSAKICBmaWx0ZXIoc2VudGltZW50ID09ICJwb3NpdGl2ZSIpKSAKcG9zX2IgPC0gYXMuZGF0YS5mcmFtZShzb3J0KHRhYmxlKHBvc19iJHdvcmQpKSkKY29sbmFtZXMocG9zX2IpIDwtIGNvbHVtbnNfc2VudGltZW50CgpuZWdfYiA8LSBseXJpY3Nfd29yZHMgJT4lCiAgaW5uZXJfam9pbihnZXRfc2VudGltZW50cygiYmluZyIpICU+JSAKICBmaWx0ZXIoc2VudGltZW50ID09ICJuZWdhdGl2ZSIpKSAKbmVnX2IgPC0gYXMuZGF0YS5mcmFtZShzb3J0KHRhYmxlKG5lZ19iJHdvcmQpKSkKY29sbmFtZXMobmVnX2IpIDwtIGNvbHVtbnNfc2VudGltZW50Cgpwb3NfbCA8LSBseXJpY3Nfd29yZHMgJT4lIAogIGlubmVyX2pvaW4oZ2V0X3NlbnRpbWVudHMoImxvdWdocmFuIikgJT4lIAogIGZpbHRlcihzZW50aW1lbnQgPT0gInBvc2l0aXZlIikpIApwb3NfbCA8LSBhcy5kYXRhLmZyYW1lKHNvcnQodGFibGUocG9zX2wkd29yZCkpKQpjb2xuYW1lcyhwb3NfbCkgPC0gY29sdW1uc19zZW50aW1lbnQKCm5lZ19sIDwtIGx5cmljc193b3JkcyAlPiUKICBpbm5lcl9qb2luKGdldF9zZW50aW1lbnRzKCJsb3VnaHJhbiIpICU+JSAKICBmaWx0ZXIoc2VudGltZW50ID09ICJuZWdhdGl2ZSIpKSAKbmVnX2wgPC0gYXMuZGF0YS5mcmFtZShzb3J0KHRhYmxlKG5lZ19sJHdvcmQpKSkKY29sbmFtZXMobmVnX2wpIDwtIGNvbHVtbnNfc2VudGltZW50CgpwMTkgPC0gZ2dwbG90KGRhdGEgPSB0YWlsKHBvc19iLCAyMCksIGFlcyh3b3JkLCBGcmVxLCBmaWxsID0gd29yZCkpICsKICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gRnJlcSksIHZqdXN0ID0gMS42LCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAzLCBhbmdsZT05MCkgKwogICAgICBnZ3RpdGxlKCJQb3NpdGl2ZSAoQklORykiKSArCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIHRpbHRfdGhlbWUKcDIwIDwtIGdncGxvdChkYXRhID0gdGFpbChuZWdfYiwgMjApLCBhZXMod29yZCwgRnJlcSwgZmlsbCA9IHdvcmQpKSArCiAgICAgIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZXEpLCB2anVzdCA9IDEuNiwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMywgYW5nbGU9OTApICsKICAgICAgZ2d0aXRsZSgiTmVnYXRpdmUgKEJJTkcpIikgKwogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICB0aWx0X3RoZW1lCnAyMSA8LSBnZ3Bsb3QoZGF0YSA9IHRhaWwocG9zX2wsIDIwKSwgYWVzKHdvcmQsIEZyZXEsIGZpbGwgPSB3b3JkKSkgKwogICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBGcmVxKSwgdmp1c3QgPSAxLjYsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMsIGFuZ2xlPTkwKSArCiAgICAgIGdndGl0bGUoIlBvc2l0aXZlIChMT1VHSFJBTikiKSArCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIHRpbHRfdGhlbWUKcDIyIDwtIGdncGxvdChkYXRhID0gdGFpbChuZWdfbCwgMjApLCBhZXMod29yZCwgRnJlcSwgZmlsbCA9IHdvcmQpKSArCiAgICAgIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZXEpLCB2anVzdCA9IDEuNiwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMywgYW5nbGU9OTApICsKICAgICAgZ2d0aXRsZSgiTmVnYXRpdmUgKExPVUdIUkFOKSIpICsKICAgICAgZ3VpZGVzKGZpbGw9RkFMU0UpICsKICAgICAgdGlsdF90aGVtZQptdWx0aXBsb3QocDE5LCBwMjAscDIxLCBwMjIsbGF5b3V0ID0gbWF0cml4KGMoMSwyLDMsNCksIG5yb3c9MiwgYnlyb3c9VFJVRSkpCgpgYGAKCkl0IGNhbiBiZSBzZWVuIHRoYXQgcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIHdvcmRzIGFyZSBkaWZmZXJlbnQgZm9yIGFsbCB0aHJlZSBsZXhpY29ucy4gCgo=